//
// Created by 67376 on 2022/12/30.
//

#ifndef CMAKELISTS_TXT_XFRAME_H
#define CMAKELISTS_TXT_XFRAME_H

#include <stdint.h>


#ifdef __cplusplus
extern "C"
{
#endif


#define META_DATA (1 << 0)          // 数据帧
#define META_DEV_REQ (1 << 1)       // 设备请求帧
#define META_DEV_RSP (1 << 2)       // 设备响应帧
#define META_SRV_REQ (1 << 3)       // 服务器请求帧
#define META_SRV_RSP (1 << 4)       // 服务器响应帧
#define META_CONNECT (1 << 8)       // 连接帧
#define META_CONNACK (1 << 9)       // 连接响应帧

#define GPS_PACKAGE 5

typedef uint32_t x32;
typedef uint16_t x16;
typedef uint8_t x8;
typedef int32_t i32;
typedef int16_t i16;
typedef int8_t i8;
typedef uint32_t x24;
typedef uint32_t c_time;

typedef int (*c_encode)(uint8_t *data, int size, int pos);


#define STR_NO_EXPAND(A) #A
#define STR(A) STR_NO_EXPAND(A)

#define CAT_NO_EXPAND(A, B) A ## B
#define CAT(A, B) CAT_NO_EXPAND(A, B)


#define TSP_FRAME_HEAD \
    X(head, 0x00, 0x00, M(x16, start) M(x16, len) M(s_arr(15), imei) M(x8, type) M(x16, seq) M(x16, effect) )

#define TSP_RX_FRAMES \
	X(connack,                                  0x02,      (META_CONNACK),                		M(x8,result) M(x32,timestamp)		)\
	X(srv_rsp_upgrade_data,                     0xf001,    (META_SRV_RSP),                		M(x8,type) M(x32,byte0) M(x32,offset)		)\
	X(srv_rsp_verify,                           0xf003,    (META_SRV_RSP),                		M(x8,type) M(c_str(64),filename) M(x32,file_size)		)\
	X(srv_rsp_weather,                          0xf00c,    (META_SRV_RSP),                		M(x8,temp) M(x8,weather)		)\
	X(srv_req_upgrade_request,                  0xf100,    (META_SRV_REQ),                		M(x8,type) M(c_str(128),addr) M(c_str(64),filename)	)\
	X(srv_req_set_param,                        0xf102,    (META_SRV_REQ),                		)\
	X(srv_req_get_param,                        0xf103,    (META_SRV_REQ),                		)\
	X(srv_req_find_car,                         0xf115,    (META_SRV_REQ),                		M(x8,byte0)		)\
	X(srv_req_ctl_lock,                         0xf113,    (META_SRV_REQ),                		M(x8,control) M(x8,cnt)		)\
    X(srv_req_manual_defence_switch,            0xf120,    (META_SRV_REQ),                		M(x8,defence_switch)		)\
	X(srv_req_check_upgrade_condition,          0xf126,    (META_SRV_REQ),                		M(x8,type) M(x32,task_id)		)\
	X(srv_req_upgrade_device,                   0xf127,    (META_SRV_REQ),                		M(x8,type) M(x32,task_id) M(x32,crc)		)\
	X(srv_rsp_common,                           0xFFFF,    (META_SRV_RSP),                		)\

#define TSP_TX_FRAMES \
    X(connect,                                  0x01,      (META_CONNECT),                		M(x16,proto) M(x16,mcu_hardver) M(c_str(64),mcu_softver) M(c_str(64),mdm_softver) M(c_str(64),mdm_hardver) M(x32,time)		)\
    X(engine_on,                                0x0001,    (META_DATA),        		            M(x8,type) M(c_time,time) M(gps_t,gps)		)\
    X(engine_off,                               0x0002,    (META_DATA),        		            M(x8,type) M(c_time,time) M(gps_t,gps)		)\
    X(theft_start,                              0x0003,    (META_DATA),                   		M(c_time,time) M(gps_t,gps)		)\
    X(theft_end,                                0x0004,    (META_DATA),                   		M(c_time,time) M(gps_t,gps)		)\
    X(diagnostic_data_stream,                   0x0009,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x8,general_data_validity) M(c_arr(33),general_data) M(x8,private_data_validity) M(c_arr(125),private_data)		)\
    X(lock_sync,                                0x000C,    (META_DATA),                   		M(c_time,time) M(x8,status)		)\
    X(vehicle_fault_light,                      0x000D,    (META_DATA),                   		M(c_time,time) M(x16,status) M(gps_t,gps)		)\
    X(dtc,                                      0x000E,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x8,version) M(x8,num) M(c_arr(96),data)		)\
    X(real_time,                                0x0010,    (META_DATA),                   		M(c_time,time) M(x8,car_state) M(x8,dev_state) M(x8,gsm_signal) M(x8,gps_signal) M(x32,battery))\
    X(realtime_vehicle_condition,               0x0012,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(c_arr(255),data)		)\
    X(rapid_acceleration,                       0x0100,    (META_DATA),                   		M(c_time,time) M(x8,pre_speed) M(x8,post_speed) M(x8,max_acceleration_value) M(gps_t,gps)		)\
    X(rapid_deceleration,                       0x0101,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x8,pre_speed) M(x8,post_speed) M(x8,max_deceleration_value)		)\
    X(rapid_turn,                               0x0102,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x8,max_turn_angle)		)\
    X(brake,                                    0x0110,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x8,brake_time)		)\
    X(fatigue_driving,                          0x0104,    (META_DATA),                   		M(c_time,time) M(gps_t,gps)		)\
    X(over_speed,                               0x0105,    (META_DATA),                   		M(c_time,time) M(x8,max_speed) M(x32,start_time) M(x32,end_time) M(gps_t,gps)		)\
    X(location,                                 0x0200,    (META_DATA),                   		M(c_gps(GPS_PACKAGE), gps) M(x16,slope_angle)		)\
    X(lbs,                                      0x0201,    (META_DATA),                   		M(c_time,time) M(x32,cellid) M(x32,lac) M(x32,mccmnc) M(x8,rssi) M(x8,network_type)		)\
    X(sleep,                                    0x0402,    (META_DATA),                   		M(c_time,time) M(x16,voltage) M(x8,voltage_source) M(gps_t,gps) M(x8,mode)		)\
    X(wakeup,                                   0x0403,    (META_DATA),                   		M(c_time,time) M(x16,voltage) M(x8,voltage_source) M(x8,wake_type) M(gps_t,gps)		)\
    X(gps_long_time_no_fix,                     0x0404,    (META_DATA),                   		M(c_time,time)		)\
    X(reset,                                    0x0405,    (META_DATA),                   		M(c_time,time) M(x8,power_on_type)		)\
    X(upgrade_status,                           0x0406,    (META_DATA),                   		M(x8,type) M(c_time,time) M(x8,status)		)\
    X(device_info,                              0x040C,    (META_DATA),                   		M(x32,time) M(c_str(8),phone) M(c_str(21),iccid) M(c_str(16),imsi) M(x8,gsm_signal) M(x8,gps_signal) M(c_str(32),bver) M(c_str(32),bname)		)\
    X(sk,                                       0x0412,    (META_DATA),                   		M(c_time,time) M(c_str(7),sk_number)		)\
    X(sk_result,                                0x0413,    (META_DATA),                   		M(c_time,time) M(x8,result)		)\
    X(low_voltage,                              0x0501,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x8,voltage)		)\
    X(shake,                                    0x0502,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x16,reserved)		)\
    X(collision,                                0x0505,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x8,value)		)\
    X(device_pull_out,                          0x0507,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x8,engine_status)		)\
    X(rollover,                                 0x0509,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(x16,reserved)		)\
    X(sensor_learn_state,                       0x0510,    (META_DATA),                   		M(c_time,time) M(x8,status)		)\
    X(long_on_unlock,                            0x0511,    (META_DATA),                   		M(c_time,time) M(gps_t,gps)	)\
    X(self_check,                               0x050a,    (META_DATA),                   		M(c_time,time) M(gps_t,gps) M(c_arr(4),result)		)\
    X(oil_truck_high_frequency,                 0x0700,    (META_DATA),                         M(c_time,time) M(x8,type) M(x16, engineSpeed) M(x16,speed) M(x32,total_mileage) M(x16,temperature) M(x8,battery_voltage) M(x8,oil_level) M(x8,throttle_opening) M(x16,ins_fuel_consumption) \
                                                                                                M(x16,o2_feedback_vol) M(x16,fuel_correction_value) M(x16,in_air_temperature) M(x16,load_calculation_values) M(x16,in_pipe_pressure) M(x8,o2_open_state) M(x8,acc_on_be)				)\
    X(oil_truck_low_frequency,                  0x0701,    (META_DATA),                         M(c_time,time) M(x16, demand_torque_signal) M(x16, current_torque_signal) M(x8, demand_torque_valid) M(x8,current_torque_valid) M(x16,gear_ratio_signal) M(x16,front_wheel_rotation) M(x16,rear_wheel_speed)			)\
    X(fault_code_ecu,                           0x0702,    (META_DATA),                         M(c_time,time) M(x8,count) M(c_arr(128),fault_data)			)\
    X(fault_code_abs,                           0x0703,    (META_DATA),                         M(c_time,time) M(x8,count) M(c_arr(128),fault_data)		)\
    X(small_battery_alarm,                      0x0513,    (META_DATA),                         M(c_time,time) M(gps_t,gps) M(x8,state)		)\
    X(dev_req_upgrade_data,                     0xf001,    (META_DEV_REQ),                		M(x8,type) M(x32,time) M(c_str(64),filename) M(x32,offset) M(x16,len) 		)\
    X(dev_req_verify,                           0xf003,    (META_DEV_REQ),                		M(x8,type) M(x32,time) M(c_str(64),filename) 		)\
    X(dev_rsp_upgrade_request,                  0xf100,    (META_DEV_RSP),                		M(x8,status)	)\
    X(dev_rsp_set_param,                        0xf102,    (META_DEV_RSP),                		M(c_encode,encode)		)\
    X(dev_rsp_get_param,                        0xf103,    (META_DEV_RSP),                		M(c_encode,encode)		)\
    X(dev_rsp_ctl_lock,                         0xf113,    (META_DEV_RSP),                		M(x8,result)		)\
    X(dev_rsp_find_car,                         0xf115,    (META_DEV_RSP),                		M(x8,result)		)\
    X(dev_rsp_manual_defence_switch,            0xf120,    (META_DEV_RSP),                		M(x8,result)		)\
    X(dev_rsp_check_upgrade_condition,          0xf126,    (META_DEV_RSP),                		M(x32 ,time) M(x8,type) M(x8,cnum) M(x8,c1) M(x8,c2) M(x8,c3) M(x32,task_id)		)\
    X(dev_rsp_upgrade_device,                   0xf127,    (META_DEV_RSP),                		M(x8,type) M(x8,result) M(x32,task_id)		)\

#pragma pack(1)

/**
 * @brief gps 结构定义
 */
typedef struct gps_t {
    /**
     * @brief 定时时间
     */
    uint32_t time;

    /**
     * @brief 定位来源 0-GPS 1-GSM
     */
    uint8_t src;

    /**
     * @brief 数据有效性 0x0-实时 0x1-最近一次
     */
    uint8_t valid;

    /**
     * @brief 东西经 0x0-东经 0x1-西经
     */
    uint8_t f_lng;

    /**
     * @brief 南北纬 0x0-南纬 0x1-北纬
     */
    uint8_t f_lat;

    /**
     * @brief 定位卫星个数
     */
    uint8_t satellites;

    /**
     * @brief 高度值
     */
    uint16_t height;

    /**
     * @brief 经度值
     */
    uint32_t lon;

    /**
     * @brief 纬度值
     */
    uint32_t lat;

    /**
     * @brief 速度值
     */
    uint16_t speed;

    /**
     * @brief 方向值
     */
    uint16_t direction;

    /**
     * @brief pdod
     */
    uint16_t pdod;

    /**
     * @brief hdop
     */
    uint16_t hdop;

    /**
     * @brief vdop
     */
    uint16_t vdop;

    /**
     * 点熄火状态
     */
    uint8_t ign_status;

    /**
     * @brief hacc
     */
    uint16_t hacc;

    uint8_t is_turn_point;
} gps_t;

#define c_arr(S) struct { uint8_t size; uint8_t arr[S]; }
#define c_str(S) struct { char str[S]; }
#define c_gps(S) struct { uint8_t cnt; gps_t gps[S]; }
#define s_arr(S) struct { char str[S]; }
#define M(L, R) L R;

#define X(S, CMD, META, ...) typedef struct frame_tx_##S##_t { __VA_ARGS__ } frame_tx_##S##_t;
TSP_TX_FRAMES
TSP_FRAME_HEAD
#undef X

#define X(S, CMD, META, ...) typedef struct frame_rx_##S##_t { __VA_ARGS__ uint8_t xxxdump;} frame_rx_##S##_t;
TSP_RX_FRAMES
TSP_FRAME_HEAD
#undef X

#undef M
#undef c_arr
#undef c_str
#undef c_gps
#undef s_arr


/**
 * @brief tx帧类型定义
 */
enum frame_tx_type_e {
    frame_tx_type_min = 0,
#define X(name, id, meta, ...) frame_tx_type_##name,
    TSP_TX_FRAMES
#undef X
    frame_tx_type_max
};

/**
 * @brief rx帧类型定义
*/
enum frame_rx_type_e {
    frame_rx_type_min = 0,
#define X(name, id, meta, ...) frame_rx_type_##name,
    TSP_RX_FRAMES
#undef X
    frame_rx_type_max
};

/**
 * @brief 帧头定义
 */
struct frame_head_t
{
    /**
     * @brief 帧类型
    */
    uint8_t type;

    /**
     * @brief 帧序号
    */
    uint16_t seq;
};

/**
 * @brief tx帧定义
 */
typedef struct frame_tx_t
{
    struct frame_head_t head;
    union
    {
#define X(name, id, meta, ...) struct frame_tx_##name##_t name;
        TSP_TX_FRAMES
#undef X
    } value;
} frame_tx_t;

/**
 * @brief rx帧定义
 */
typedef struct frame_rx_t
{
    struct frame_head_t head;
    union
    {
#define X(name, id, meta, ...) struct frame_rx_##name##_t name;
        TSP_RX_FRAMES
#undef X
    } value;
} frame_rx_t;

#pragma pack()

/**
 * @brief 帧信息定义
 */
typedef struct frame_info_t
{
    /**
     * @brief 帧描述
     */
    const char *desc;

    /**
     * @brief 帧大小
     */
    uint16_t size;

    /**
     * @brief 帧元信息
     */
    uint16_t meta;

    /**
     * @brief 帧命令
     */
    uint16_t cmd;

    /**
     * @brief 帧编解码函数联合体
     */
    union {
        /**
         * @brief 帧编码函数指针
         * @param buf 缓冲区
         * @param size 缓冲区大小
         * @param pos 当前位置
         * @param o 帧指针
         */
        int (*encode)(unsigned char *buf, int size, int pos, const void *o);

        /**
         * @brief 帧解码函数指针
         * @param buf 缓冲区
         * @param size 缓冲区大小
         * @param pos 当前位置
         * @param o 帧指针
         */
        int (*decode)(const unsigned char *buf, int size, int pos, void *o);
    } codec;
} frame_info_t;

/**
 * @brief 获取帧信息
 * @param type 帧类型
 * @return 成功返回帧信息指针，失败返回NULL
 */
const struct frame_info_t *frame_tx_get_info(uint8_t type);

/**
 * @brief 获取帧大小
 * @param type 帧类型
 * @return 成功返回帧大小，失败返回0
 */
int frame_tx_get_size(uint8_t type);

/**
 * @brief 根据帧类型创建帧
 * @param type 帧类型
 * @return 成功返回帧指针，失败返回NULL
 */
struct frame_tx_t *frame_tx_create(uint8_t type);

/**
 * @brief 销毁帧
 * @param frame 帧指针
 */
void frame_tx_destroy(struct frame_tx_t *frame);

/**
 * @brief 编码帧
 * @param frame 帧指针
 * @param data 编码后的数据
 * @param len data数据长度
 * @return 成功返回编码后的数据长度，失败返回-1
 */
int frame_tx_encode(const struct frame_tx_t *frame, uint8_t *data, int len);

/**
 * @brief 解码帧
 * @param payload 帧数据
 * @param size 帧数据长度
 * @return 成功返回帧数据长度，失败返回-1
 */
int frame_rx_decode(const uint8_t *payload, int size);

#ifdef __cplusplus
}
#endif

#endif // CMAKELISTS_TXT_XFRAME_H
